<template>
  <canvas :width="width" :height="height" ref="canvasRef"></canvas>
  <br />
  <br />
  <button @click="onRenderTriStart">开始</button>
  <br />
  <button @click="onRenderTriEnd">结束</button>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
import * as GLMatrix from "gl-matrix";

const width = ref<number>(600);
const height = ref<number>(600);
const canvasRef = ref<HTMLCanvasElement>();
const glRef = ref<WebGLRenderingContext>();
const proRef = ref<WebGLProgram>();
const taskId = ref<number>()

const tranValue = ref<GLMatrix.mat4>(GLMatrix.mat4.create());

onMounted(() => {
  init();
});

const init = () => { // 顶点着色器  偏移量为屏幕坐标系
  const gl = canvasRef.value?.getContext("webgl");
  if (!gl) return;
  gl.viewport(0, 0, width.value, height.value);

  const veString = `
    attribute vec4 a_position;
    uniform mat4 viewPro;
    uniform mat4 tran; // 矩阵
    void main(void){
      gl_Position = tran * viewPro * a_position ;
      gl_PointSize = 1.0;
    }
  `;

  const frString = `
    void main(void){
      gl_FragColor = vec4(1.0,1.0,0.0,1.0);
    }
  `;
  const veShader = gl.createShader(gl.VERTEX_SHADER);
  if (!veShader) return;
  gl.shaderSource(veShader, veString);
  gl.compileShader(veShader);

  if (!gl.getShaderParameter(veShader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(veShader) || "");
  }

  const frShader = gl.createShader(gl.FRAGMENT_SHADER);
  if (!frShader) return;
  gl.shaderSource(frShader, frString);
  gl.compileShader(frShader);

  const pro = gl.createProgram();
  if (!pro) return;
  gl.attachShader(pro, veShader);
  gl.attachShader(pro, frShader);
  gl.linkProgram(pro);
  gl.useProgram(pro);


  const mat4 = GLMatrix.mat4.create();
  GLMatrix.mat4.ortho(mat4, 0, width.value, height.value, 0, -1, 1);

  const view = gl.getUniformLocation(pro, "viewPro");
  gl.uniformMatrix4fv(view, false, mat4);


  const points = new Float32Array([150, 300, 300, 590, 0, 590]);
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  const a_position = gl.getAttribLocation(pro, "a_position");
  gl.enableVertexAttribArray(a_position);
  gl.vertexAttribPointer(a_position, 2, gl.FLOAT, true, 0, 0);

  // init
  const tran = gl.getUniformLocation(pro, 'tran');
  gl.uniformMatrix4fv(tran, false, tranValue.value)

  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.drawArrays(gl.TRIANGLES, 0, points.length / 2)

  glRef.value = gl;
  proRef.value = pro;
};

const direc = new Date().getTime();

const taskQueue = () => {
  if (!glRef.value) return;
  if (!proRef.value) return;
  const gl = glRef.value;
  const pro = proRef.value;
  const tran = gl.getUniformLocation(pro, 'tran');
  const dir = (Math.floor((new Date().getTime() - direc) / 2000)) % 4

  const transs: [number, number, number] = dir === 0 ? [0, 0.005, 0] : dir === 1 ? [0.005, 0, 0] : dir === 2 ? [0, -0.005,0] : [-0.005, 0, 0]
  GLMatrix.mat4.translate(tranValue.value, tranValue.value, transs);
  gl.uniformMatrix4fv(tran, false, tranValue.value)

  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.drawArrays(gl.TRIANGLES, 0, 3)
  taskId.value = requestAnimationFrame(taskQueue)
}

const onRenderTriStart = () => {
  onRenderTriEnd();
  tranValue.value = GLMatrix.mat4.create();
  taskId.value = requestAnimationFrame(taskQueue)
};

const onRenderTriEnd = () => {
  taskId.value && cancelAnimationFrame(taskId.value)
  taskId.value = 0;
}


</script>

<style></style>
